﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace ProgramMain.Google
{
    public class CoordinateRectangle : ICloneable
    {
        public static readonly CoordinateRectangle Empty = new CoordinateRectangle();

        public Coordinate LeftTop
        {
            get
            {
                return new Coordinate(Left, Top);
            }
        }

        public Coordinate RightBottom
        {
            get
            {
                return new Coordinate(Right, Bottom);
            }
        }

        public Coordinate LeftBottom
        {
            get
            {
                return new Coordinate(Left, Bottom);
            }
        }

        public Coordinate RightTop
        {
            get
            {
                return new Coordinate(Right, Top);
            }
        }

        public double Left { get; private set; }

        public double Right { get; private set; }

        public double Top { get; private set; }

        public double Bottom { get; private set; }

        private CoordinateRectangle()
        {
            Bottom = 0;
            Top = 0;
            Right = 0;
            Left = 0;
        }

        public CoordinateRectangle(double Left, double Top, double Right, double Bottom)
        {
            this.Left = Left;
            this.Top = Top;
            this.Right = Right;
            this.Bottom = Bottom;
        }

        public CoordinateRectangle(decimal Left, decimal Top, decimal Right, decimal Bottom)
        {
            this.Left = (double)Left;
            this.Top = (double)Top;
            this.Right = (double)Right;
            this.Bottom = (double)Bottom;
        }

        public CoordinateRectangle(Coordinate pLeftTop, Coordinate pRightBottom)
        {
            Left = pLeftTop.Longitude;
            Top = pLeftTop.Latitude;
            Right = pRightBottom.Longitude;
            Bottom = pRightBottom.Latitude;
        }

        #region ICloneable Members
        public object Clone()
        {
            return new CoordinateRectangle(Left, Top, Right, Bottom);
        }
        #endregion

        public Rectangle GetScreenRect(GoogleRectangle googleScreenView)
        {
            return new GoogleRectangle(this, googleScreenView.Level).GetScreenRect(googleScreenView);
        }

        public InterseptResult PointContains(Coordinate point)
        {
            return (point.Longitude >= Left
                && point.Longitude <= Right
                && point.Latitude <= Top
                && point.Latitude >= Bottom) ? InterseptResult.Contains : InterseptResult.None;
        }

        public InterseptResult RectangleContains(CoordinateRectangle rectangle)
        {
            bool iLeftTop = PointContains(rectangle.LeftTop) != InterseptResult.None;
            bool iRightBottom = PointContains(rectangle.RightBottom) != InterseptResult.None;

            if (iLeftTop && iRightBottom)
                return InterseptResult.Contains;
            if (iLeftTop || iRightBottom)
                return InterseptResult.Intersepts;

            if (PointContains(rectangle.LeftBottom) != InterseptResult.None)
                return InterseptResult.Intersepts;
            if (PointContains(rectangle.RightTop) != InterseptResult.None)
                return InterseptResult.Intersepts;

            iLeftTop = rectangle.PointContains(this.LeftTop) != InterseptResult.None;
            iRightBottom = rectangle.PointContains(this.RightBottom) != InterseptResult.None;

            if (iLeftTop && iRightBottom)
                return InterseptResult.Supersets;
            if (iLeftTop || iRightBottom)
                return InterseptResult.Intersepts;

            if (rectangle.PointContains(this.LeftBottom) != InterseptResult.None)
                return InterseptResult.Intersepts;
            if (rectangle.PointContains(this.RightTop) != InterseptResult.None)
                return InterseptResult.Intersepts;

            if (MapUtilities.CheckLinesInterseption(new CoordinateRectangle(Left, Top, Left, Bottom),
                    new CoordinateRectangle(rectangle.Left, rectangle.Top, rectangle.Right, rectangle.Top)))
                return InterseptResult.Intersepts;
            if (MapUtilities.CheckLinesInterseption(new CoordinateRectangle(Left, Top, Right, Top),
                    new CoordinateRectangle(rectangle.Left, rectangle.Top, rectangle.Left, rectangle.Bottom)))
                return InterseptResult.Intersepts;

            return InterseptResult.None;
        }

        public InterseptResult LineContains(CoordinateRectangle line)
        {
            bool iLeftTop = PointContains(line.LeftTop) != InterseptResult.None;
            bool iRightBottom = PointContains(line.RightBottom) != InterseptResult.None;

            if (iLeftTop && iRightBottom)
                return InterseptResult.Contains;
            else if (iLeftTop || iRightBottom)
                return InterseptResult.Intersepts;
            else if (MapUtilities.CheckLinesInterseption(new CoordinateRectangle(Left, Top, Right, Top), line))
                return InterseptResult.Intersepts;
            else if (MapUtilities.CheckLinesInterseption(new CoordinateRectangle(Right, Top, Right, Bottom), line))
                return InterseptResult.Intersepts;
            else if (MapUtilities.CheckLinesInterseption(new CoordinateRectangle(Left, Bottom, Right, Bottom), line))
                return InterseptResult.Intersepts;
            else if (MapUtilities.CheckLinesInterseption(new CoordinateRectangle(Left, Top, Left, Bottom), line))
                return InterseptResult.Intersepts;
            else
                return InterseptResult.None;
        }

        public double RectangeDistance(Coordinate coordinate)
        {
            if (PointContains(coordinate) != InterseptResult.None)
                return 0;

            double min = EarthUtilities.GetDistance(new CoordinateRectangle(Left, Top, Right, Top), coordinate);
            double res = EarthUtilities.GetDistance(new CoordinateRectangle(Right, Top, Right, Bottom), coordinate);
            if (res < min) min = res;
            res = EarthUtilities.GetDistance(new CoordinateRectangle(Right, Bottom, Left, Bottom), coordinate);
            if (res < min) min = res;
            res = EarthUtilities.GetDistance(new CoordinateRectangle(Left, Bottom, Left, Top), coordinate);
            if (res < min) min = res;

            return min;
        }

        public double LineDistance(Coordinate coordinate)
        {
            return EarthUtilities.GetDistance(this, coordinate);
        }

        public Coordinate LineMiddlePoint()
        {
            return MapUtilities.GetMiddlePoint(this.LeftTop, this.RightBottom);
        }

        public double LineLength()
        {
            return this.LeftTop.Distance(this.RightBottom);
        }

        public double Width
        {
            get { return Right - Left; }
        }

        public double Height
        {
            get { return Bottom - Top; }
        }

        public double Angle
        {
            get { return Math.Atan2(Width, Height); }
        }

        public void AddDistance(double metre)
        {
            double d = LeftTop.Distance(RightBottom);
            Right = Left + (d + metre) * Math.Cos(Angle);
            Bottom = Top + (d + metre) * Math.Sin(Angle);
        }

        public Coordinate GetNearestPoint(Coordinate pt)
        {
            int ruleDistance = Properties.Settings.Default.PutRuleDistance;
            if (EarthUtilities.GetDistance(this, pt) > ruleDistance)
            {
                return pt;
            }
            return EarthUtilities.GetNearestPoint(this, pt);
        }
    }
}